package com.jinly.ryder.log.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jinly.ryder.common.error.SystemErrorType;
import com.jinly.ryder.common.service.SystemSettingService;
import com.jinly.ryder.common.service.model.setting.TencentSetting;
import com.jinly.ryder.common.utils.DateUtil;
import com.jinly.ryder.log.service.LogSearchService;
import com.jinly.ryder.log.service.model.ContextQuery;
import com.jinly.ryder.log.service.model.LogContent;
import com.jinly.ryder.log.service.model.SearchQuery;
import com.jinly.ryder.log.service.model.SearchResult;
import com.tencentcloudapi.cls.v20201016.ClsClient;
import com.tencentcloudapi.cls.v20201016.models.*;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 腾讯云日志搜索
 */
@Slf4j
@Service("clsLogSearchService")
@RequiredArgsConstructor
public class ClsLogSearchServiceImpl implements LogSearchService {

    private final SystemSettingService systemSettingService;
    private ClsClient clsClient;
    private TencentSetting tencentSetting;

    private Map<String, String> appNameTopicMap = new HashMap<>();

    @Override
    public SearchResult search(SearchQuery query) {
        SearchLogRequest req = new SearchLogRequest();
        req.setTopicId(getTopicId(query.getAppName()));
        req.setFrom(query.getFrom());//开始时间
        req.setTo(query.getTo());//开始时间
        List<String> querys = new ArrayList<>();
        if (!ObjectUtils.isEmpty(query.getLevel())) {
            querys.add("level:" + query.getLevel());
        }
        if (!ObjectUtils.isEmpty(query.getKeyword())) {
            querys.add("content:*" + query.getKeyword() + "*");
        }
        req.setQuery(querys.stream().collect(Collectors.joining(" AND ")));
        req.setLimit(query.getSize());
        req.setContext(query.getContext());
        SearchResult result = null;
        try {
            SearchLogResponse resp = getClient().SearchLog(req);
            if (resp.getAnalysisResults() != null && resp.getResults() != null) {
                result = new SearchResult();
                List<LogContent> logContents = new ArrayList<>();
                for (int i = 0; i < resp.getResults().length; i++) {
                    LogInfo logInfo = resp.getResults()[i];
                    JSONObject jsonObject = JSON.parseObject(logInfo.getLogJson());
                    LogContent logContent = new LogContent();
                    logContent.setTime(logInfo.getTime());
                    logContent.setLevel(jsonObject.getString("level"));
                    logContent.setContent(jsonObject.getString("content"));
                    logContent.setSource(logInfo.getSource());
                    logContent.setPkgId(logInfo.getPkgId());
                    logContent.setPkgLogId(Long.valueOf(logInfo.getPkgLogId()));
                    logContents.add(logContent);
                }
                result.setLogContents(logContents);
                result.setContext(resp.getContext());
                result.setListOver(resp.getListOver());
            }

        } catch (Exception e) {
            log.error("查询日志失败", e);
        }
        return result;
    }

    @Override
    public List<LogContent> logContextList(ContextQuery query) {
        DescribeLogContextRequest req = new DescribeLogContextRequest();
        req.setTopicId(getTopicId(query.getAppName()));
        req.setBTime(DateUtil.toLocal(query.getTime()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        req.setPkgId(query.getPkgId());
        req.setPkgLogId(query.getPkgLogId());
        req.setPrevLogs(query.getPrevLogs());
        req.setNextLogs(query.getNextLogs());
        List<LogContent> list = new ArrayList<>();
        try {
            DescribeLogContextResponse resp = getClient().DescribeLogContext(req);
            list = Arrays.stream(resp.getLogContextInfos()).map(c -> {
                JSONObject jsonObject = JSON.parseObject(c.getContent());
                LogContent content = new LogContent();
                content.setTime(c.getBTime());
                content.setContent(jsonObject.getString("content"));
                content.setLevel(jsonObject.getString("level"));
                content.setSource(c.getSource());
                content.setPkgId(c.getPkgId());
                content.setPkgLogId(c.getPkgLogId());
                return content;
            }).collect(Collectors.toList());
        } catch (Exception e) {
            log.error("查询日志失败", e);
        }
        return list;
    }

    private String getTopicId(String appName) {
        String topicId = null;
        if (appNameTopicMap.containsKey(appName)) return appNameTopicMap.get(appName);
        DescribeTopicsRequest req = new DescribeTopicsRequest();
        Filter f = new Filter();
        f.setKey("topicName");
        f.setValues(new String[]{appName});
        req.setFilters(new Filter[]{f});
        try {
            DescribeTopicsResponse resp = getClient().DescribeTopics(req);
            if (resp.getTotalCount() == 1) {
                topicId = resp.getTopics()[0].getTopicId();
                appNameTopicMap.put(appName, topicId);
            }
        } catch (Exception e) {
            log.error("查询日志主题失败", e);
        }
        return topicId;
    }

    private synchronized ClsClient getClient() {
        if (clsClient != null) return clsClient;
        try {
            tencentSetting = systemSettingService.getSettingItem(TencentSetting.class);
            Credential cred = new Credential(tencentSetting.getSecretId(), tencentSetting.getSecretKey());
            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setEndpoint("cls.tencentcloudapi.com");
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);
            clsClient = new ClsClient(cred, tencentSetting.getRegion(), clientProfile);
            return clsClient;
        } catch (Exception e) {
            log.error("初始化腾讯云客户端失败:{}", e.getMessage());
            throw SystemErrorType.INTERNAL_SERVER_ERROR.buildError();
        }
    }
}
